Skip to content

Perbaikan data desa tidak tampil / tidak sesuai filter saat membuka halaman Desa dari Dasbor - #1266

Merged
analisopendesa merged 4 commits into
rilis-devfrom
1265-data-desa-tidak-tampil
Aug 19, 2026
Merged

Perbaikan data desa tidak tampil / tidak sesuai filter saat membuka halaman Desa dari Dasbor#1266
analisopendesa merged 4 commits into
rilis-devfrom
1265-data-desa-tidak-tampil

Conversation

@habibie11

Copy link
Copy Markdown
Contributor

issue # #1265

🎯 Deskripsi

Pull request ini memperbaiki bug pada alur navigasi dari Dasbor menuju halaman Data Desa (/desa), di mana daftar desa pada DataTable tidak menampilkan data yang sesuai dengan parameter filter yang dikirim (bahkan tabel bisa kosong sama sekali).

Terdapat tiga akar masalah yang diperbaiki:

  1. Parameter filter[kode_desa]=null terkirim sebagai string literal. Handler klik "Selengkapnya" pada kartu dasbor memanggil URLSearchParams.set() untuk semua key filter termasuk yang kosong. Karena set(name, null) mengonversi null menjadi string "null", URL yang dihasilkan berisi filter[kode_desa]=null. Controller kemudian merender <option value="null"> pada select desa, dan request DataTable mengirim nilai "null" tersebut sehingga exact match filter desa di API gagal.

  2. DataTable halaman desa mengirim sort=undefined. Konfigurasi tabel memakai ordering: true tanpa order awal, sehingga DataTables memakai default [[0, 'asc']] pada kolom No yang tidak memiliki name. Akibatnya parameter sort dihitung menjadi "undefined" pada setiap request, ditolak oleh API (spatie QueryBuilder allowedSorts) dengan status 400, dan tabel tidak pernah menampilkan data.

  3. Filter kecamatan/desa dari URL hilang setelah halaman dimuat. Script wilayah filter men-trigger ulang select kabupaten secara asynchronous saat memuat daftar kabupaten. Cascade empty() pada handler change menghapus opsi kecamatan/desa yang sudah dirender server dari parameter URL. Selain itu, isAutoLoad mengeklik #bt_filter yang tidak ada di halaman desa (tombol filternya bernama #filter), sehingga DataTable tidak pernah di-redraw dengan filter hasil restore.


🛠️ Perubahan yang Dilakukan

1. resources/views/dasbor/summary.blade.php

Fix — Hanya mengirim parameter filter yang terisi saat klik "Selengkapnya":

  • Nilai data('filter') pada kartu dinormalisasi dengan || '' agar tidak pernah bernilai null.
  • Handler klik kartu kini hanya memanggil searchParams.set() untuk key yang tidak kosong, sehingga URL tidak lagi memuat filter[kode_desa]=null.
                             .data(
                                 'filter', {
-                                    'kode_kabupaten': kabupaten,
-                                    'kode_kecamatan': kecamatan,
-                                    'kode_desa': desa,
+                                    'kode_kabupaten': kabupaten || '',
+                                    'kode_kecamatan': kecamatan || '',
+                                    'kode_desa': desa || '',
-                _url.searchParams.set('filter[kode_kabupaten]', $(this).data('filter')['kode_kabupaten']);
-                _url.searchParams.set('filter[kode_kecamatan]', $(this).data('filter')['kode_kecamatan']);
-                _url.searchParams.set('filter[kode_desa]', $(this).data('filter')['kode_desa']);
-                _url.searchParams.set('filter[nama_kabupaten]', $(this).data('filter')['nama_kabupaten']);
-                _url.searchParams.set('filter[nama_kecamatan]', $(this).data('filter')['nama_kecamatan']);
-                _url.searchParams.set('filter[nama_desa]', $(this).data('filter')['nama_desa']);
+                let filter = $(this).data('filter');
+                ['kode_kabupaten', 'kode_kecamatan', 'kode_desa', 'nama_kabupaten', 'nama_kecamatan', 'nama_desa']
+                    .forEach(function(key) {
+                        if (filter[key]) {
+                            _url.searchParams.set('filter[' + key + ']', filter[key]);
+                        }
+                    });

2. app/Http/Controllers/DesaController.php

Fix — Normalisasi nilai filter string "null"/"undefined" menjadi null:

  • Filter yang diterima dari query string dinormalisasi sehingga select tidak lagi merender option value="null" dan DataTable tidak mengirim nilai "null" sebagai filter.
         $filters = request('filter', [
             'kode_kabupaten' => null,
             'kode_desa' => null,
             'kode_kecamatan' => null,
         ]);
 
+        $filters = collect($filters)->map(function ($value) {
+            return in_array($value, ['null', 'undefined'], true) ? null : $value;
+        })->all();
+
         return view('desa.index', compact('filters'));

3. resources/views/desa/index.blade.php

Fix — Konfigurasi DataTable halaman desa:

  • Menambahkan order: [[1, 'asc']] (urutkan berdasarkan nama desa) sehingga request pertama mengirim sort=nama_desa yang valid, bukan sort=undefined.
  • Menambahkan headers: header (Bearer token API) agar konsisten dengan halaman lain (penduduk/keluarga).
  • Normalisasi nilai select dengan || '' agar tidak mengirim nilai null/undefined.
  • Guard pada parameter sort: hanya dikirim jika kolom target memiliki name (selain itu di-skip).
  • columnDefs orderable: false dipersempit hanya untuk kolom No (target 0); kolom nama desa, nama kecamatan, dan jumlah penduduk tetap dapat diurutkan sesuai desain awal fitur sort.
  • Tombol reset kini mengosongkan ketiga select (kabupaten, kecamatan, desa) — sebelumnya kabupaten dikosongkan tiga kali.
                 autoWidth: false,
                 ordering: true,
+                order: [
+                    [1, 'asc']
+                ],
                 ajax: {
                     url: urlPenduduk,
+                    headers: header,
                     method: 'get',
                     data: function(row) {
                         return {
                             "page[size]": row.length,
                             "page[number]": (row.start / row.length) + 1,
                             "filter[search]": row.search.value,
-                            "filter[kode_kabupaten]": $("#filter_kabupaten").val(),
-                            "filter[kode_kecamatan]": $("#filter_kecamatan").val(),
-                            "filter[kode_desa]": $("#filter_desa").val(),
-                            "sort": (row.order[0]?.dir === "asc" ? "" : "-") + row.columns[row
+                            "filter[kode_kabupaten]": $("#filter_kabupaten").val() || '',
+                            "filter[kode_kecamatan]": $("#filter_kecamatan").val() || '',
+                            "filter[kode_desa]": $("#filter_desa").val() || '',
+                            "sort": row.columns[row.order[0]?.column]?.name ?
+                                (row.order[0]?.dir === "asc" ? "" : "-") + row.columns[row
                                     .order[0]
                                     ?.column]
-                                ?.name
+                                ?.name : undefined
                     {
-                        targets: [0, 1, 2, 3],
+                        targets: 0,
                         orderable: false,
                         searchable: false,
                     },
             $(document).on('click', '#reset', function(e) {
                 e.preventDefault();
                 $('#filter_kabupaten').val('').change();
-                $('#filter_kabupaten').val('').change();
-                $('#filter_kabupaten').val('').change();
+                $('#filter_kecamatan').val('').change();
+                $('#filter_desa').val('').change();
 
                 pendudukDatatable.ajax.reload();
             });

4. resources/views/components/wilayah_filter_js.blade.php

Fix — Restore filter dari URL dan redraw tabel setelah cascade selesai:

  • queryKodeKabupaten, queryKodeKecamatan, dan queryKodeDesa dibaca dari window.location.search di scope top-level handler (sebelumnya queryKodeKabupaten hanya tersedia di dalam callback kabupaten).
  • Menambahkan flag urlFilterRestoring yang hanya aktif saat kabupaten di-restore dari URL, sehingga pemilihan kecamatan/desa dari URL tidak mengganggu alur normal.
  • Setelah daftar kecamatan dimuat, select kecamatan dipilih sesuai filter[kode_kecamatan] dari URL lalu trigger('change'); pola yang sama diterapkan untuk desa (filter[kode_desa]).
  • isAutoLoad kini mengeklik #bt_filter, #filter sekaligus — halaman desa yang memiliki tombol filter #filter ikut ter-redraw dengan nilai filter hasil restore (halaman lain yang hanya memiliki #bt_filter tetap berperilaku sama seperti sebelumnya).
             const identitasOpenkab = $(`meta[name="${AJAX_PARAMS_CONFIG.metaTagName}"]`).attr('content') || '';
             let isAutoLoad = false;
+            let urlFilterRestoring = false;
+            const queryKodeKabupaten = new URLSearchParams(window.location.search).get('filter[kode_kabupaten]');
+            const queryKodeKecamatan = new URLSearchParams(window.location.search).get('filter[kode_kecamatan]');
+            const queryKodeDesa = new URLSearchParams(window.location.search).get('filter[kode_desa]');
                     if (data[i].kode_kabupaten === filterValue) {
                         isAutoLoad = true;
+                        urlFilterRestoring = true;
                         $("#filter_kabupaten").val(filterValue).trigger('change');
                     }
                         $('#filter_kecamatan').prop('disabled', false);
+                        if (urlFilterRestoring && queryKodeKecamatan) {
+                            $('#filter_kecamatan').val(queryKodeKecamatan);
+                            if ($('#filter_kecamatan').val() === queryKodeKecamatan) {
+                                $('#filter_kecamatan').trigger('change');
+                            } else {
+                                urlFilterRestoring = false;
+                            }
+                        } else {
+                            urlFilterRestoring = false;
+                        }
                         if (isAutoLoad) {
-                            $('#bt_filter').trigger('click');
+                            $('#bt_filter, #filter').trigger('click');
                             isAutoLoad = false;
                         }
                         $('#filter_desa').prop('disabled', false);
+                        if (urlFilterRestoring && queryKodeDesa) {
+                            $('#filter_desa').val(queryKodeDesa);
+                            $('#filter_desa').trigger('change');
+                        }
+                        urlFilterRestoring = false;

5. tests/Feature/DesaControllerTest.php

Test — Penambahan feature test untuk halaman Desa:

  • it_returns_200_on_desa_index() — memastikan halaman /desa dapat diakses dan merender view desa.index.
  • it_normalizes_null_string_filter_values() — memastikan nilai filter "null" dari query string dinormalisasi menjadi null pada controller.
  • it_does_not_render_option_with_null_string_value() — memastikan view tidak merender <option value="null"> dan tetap menampilkan opsi kabupaten dari URL.

✅ Test Cases yang Diimplementasikan

  • Klik Selengkapnya pada kartu desa di dasbor menghasilkan URL /desa yang hanya berisi parameter filter terisi (tidak lagi filter[kode_desa]=null).
  • Buka /desa dengan filter[kode_kabupaten]=5102 → tabel menampilkan seluruh desa pada kabupaten tersebut.
  • Buka /desa dengan filter[kode_kecamatan] dan/atau filter[kode_desa] → select filter ter-restore dari URL dan tabel menampilkan data yang sesuai.
  • Request pertama DataTable halaman desa mengirim sort=nama_desa (bukan sort=undefined) sehingga API membalas 200, bukan 400.
  • Sorting pada kolom nama desa, nama kecamatan, dan jumlah penduduk tetap berfungsi.
  • Tombol reset mengosongkan filter kabupaten, kecamatan, dan desa sekaligus.
  • Feature test DesaControllerTest dan DasborControllerTest lulus (6 passed, 13 assertions).

📸 Cara Menjalankan Uji Coba Manual

  1. Login ke aplikasi OpenKab dan pastikan API Database Gabungan berjalan.
  2. Buka halaman Dasbor (/dasbor), lalu pilih kabupaten (dan opsional kecamatan/desa) pada filter wilayah.
  3. Klik Selengkapnya pada kartu Desa.
    • Seharusnya: URL berisi parameter filter yang terisi saja, contoh: ?filter[kode_kabupaten]=5102&filter[nama_kabupaten]=TABANAN.
  4. Di halaman /desa, periksa tabel Data Desa:
    • Seharusnya: DataTable menampilkan data sesuai parameter (desa pada kabupaten/kecamatan/desa yang dipilih), tidak kosong.
    • Seharusnya: Select filter kabupaten/kecamatan/desa menampilkan nilai yang sama dengan parameter URL.
    • Seharusnya: Klik header kolom nama desa/kecamatan/jumlah penduduk dapat mengurutkan data tanpa error.
  5. Klik tombol filter (search) dan reset — pastikan tabel mengikuti perubahan filter dengan benar.

🤖 Cara Menjalankan Uji Coba Otomatis (Automated Test)

php artisan test tests/Feature/DesaControllerTest.php
php artisan test tests/Feature/DasborControllerTest.php

📸 Screenshot atau Video

openkabtest.mp4

⚠️ Catatan Penting

Perubahan pada PR ini seluruhnya berada di sisi consumer (OpenKab); tidak ada perubahan kontrak atau kode pada API-Database-Gabungan.

Bug sort=undefined muncul sejak fitur sort pada tabel desa ditambahkan (ordering: true tanpa order awal). Karena seluruh kolom awalnya dibuat non-orderable, DataTables tetap mengirim urutan default kolom No yang tidak memiliki name, dan request pertama selalu ditolak API dengan 400.

@habibie11
habibie11 requested a review from vickyrolanda August 19, 2026 07:53
@github-actions

Copy link
Copy Markdown

🔄 AI PR Review sedang antri di server...

Proses review akan segera dimulai di background — hasil akan muncul sebagai komentar setelah selesai.
Powered by CrewAI · PR #1266

@analisopendesa
analisopendesa merged commit 580cdb6 into rilis-dev Aug 19, 2026
@analisopendesa
analisopendesa deleted the 1265-data-desa-tidak-tampil branch August 19, 2026 08:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants